{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using the Simulationarchive to restart a simulation\n",
    "The Simulationarchive (SA) is a binary file that can be used to restart a simulation. This can be useful when running a long simulation. REBOUND can restart simulation *exactly* (bit by bit) when using a SA. There are some restriction to when a SA can be used. Please read the corresponding paper (Rein & Tamayo 2017) for details. \n",
    "\n",
    "We first setup a simulation in the normal way. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import rebound\n",
    "\n",
    "sim = rebound.Simulation()\n",
    "sim.integrator = \"whfast\"\n",
    "sim.dt = 2.*3.1415/365.*6 # 6 days in units where G=1\n",
    "sim.add(m=1.)\n",
    "sim.add(m=1e-3,a=1.)\n",
    "sim.add(m=5e-3,a=2.25)\n",
    "sim.move_to_com()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We then initialize the SA and specify the output filename and output cadence. We can choose the output interval to either correspond to constant intervals in walltime (in seconds) or simulation time. Here, we choose walltime. To choose simulation time instead replace the `walltime` argument with `interval`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "sim.save_to_file(\"simulationarchive.bin\", walltime=1.,delete_file=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we can run the simulation forward in time. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "sim.integrate(2e5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Depending on how fast your computer is, the above command may take a couple of seconds. Once the simulation is done, we can delete it from memory and load it back in from the SA. You could do this at a later time. Note that this will even work if the SA file was generated on a different computer with a different operating system and even a different version of REBOUND. See Rein & Tamayo (2017) for a full discussion on machine independent code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time after loading simulation 175478.9\n"
     ]
    }
   ],
   "source": [
    "sim = None\n",
    "sim = rebound.Simulation(\"simulationarchive.bin\")\n",
    "print(\"Time after loading simulation %.1f\" %sim.t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we want to integrate the simulation further in time and append snapshots to the same SA, then we need to call the `save_to_file` method again (this is a fail-safe mechanism to avoid accidentally modifying a SA file). Note that we set the `delete_file` flag to `False`. Otherwise, we would create a new empty SA file. This outputs a warning because the file already exists (which is ok since we want to append that file)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/rein/git/rebound/rebound/simulation.py:525: RuntimeWarning: File in use for Simulationarchive already exists. Snapshots will be appended.\n",
      "  warnings.warn(msg[1:], RuntimeWarning)\n"
     ]
    }
   ],
   "source": [
    "sim.save_to_file(\"simulationarchive.bin\", walltime=1.,delete_file=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, let's integrate the simulation further in time. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "sim.integrate(sim.t+2e5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we repeat the process, one can see that the SA binary file now includes the new snapshots from the restarted simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time after loading simulation 352418.7\n"
     ]
    }
   ],
   "source": [
    "sim = None\n",
    "sim = rebound.Simulation(\"simulationarchive.bin\")\n",
    "print(\"Time after loading simulation %.1f\" %sim.t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A few things to note when restarting a simulation from a SA: \n",
    "- If you used any additional forces or post-timestep modifications in the original simulation, then those need to be restored after loading a simulation from a SA. A RuntimeWarning may be given related to this indicating the need to reset function pointers after creating a reb_simulation struct with a binary file.\n",
    "- If you use the symplectic WHFast integrator with the safe mode turned off, then the simulation will be in an unsynchronized state after reloading it. If you want to generate an output, then the simulation needs to be synchronized beforehand. See the WHFast tutorial on how to do that.\n",
    "- If you use the symplectic WHFast integrator with the safe mode turned off in order to combine kepler steps (see the Advanced WHFast tutorial), but want to preserve bitwise reproducibility when integrating to different times in the simulation or to match Simulationarchive snapshots, you need to manually set sim.ri_whfast.keep_unsynchronized = 1. This ensures that the integration state does not change depending on if and when you generate outputs.\n",
    "- For reproducibility, the Simulationarchive does not output snapshots at the *exact* intervals specified, but rather at the timestep in the integration directly following each interval. This means that if you load from a Simulationarchive and want to reproduce the state in a snapshot later on, you have to pass `exact_finish_time=0` in a call to `sim.integrate`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
